package com.zbkj.service.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.zbkj.common.constants.BankEnterpriseConstants;
import com.zbkj.common.constants.Constants;
import com.zbkj.common.constants.PayConstants;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.bte.PlatformResponse;
import com.zbkj.common.model.bte.Refund;
import com.zbkj.common.model.bte.WechatPayUniqueEntity;
import com.zbkj.common.model.finance.UserRecharge;
import com.zbkj.common.model.order.StoreOrder;
import com.zbkj.common.model.user.UserToken;
import com.zbkj.common.model.wechat.WechatPayInfo;
import com.zbkj.common.request.StoreOrderRefundRequest;
import com.zbkj.common.utils.CrmebUtil;
import com.zbkj.common.utils.JsonUtils;
import com.zbkj.common.utils.SHA256Utils;
import com.zbkj.service.service.BankEnterprisePaymentService;
import com.zbkj.service.service.SystemConfigService;
import com.zbkj.service.service.UserTokenService;
import com.zbkj.service.service.WechatPayInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * 银企支付服务实现
 *
 * @author Swallows
 * @date 2022-08-23 11:19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BankEnterprisePaymentServiceImpl implements BankEnterprisePaymentService {

    private final UserTokenService userTokenService;
    private final SystemConfigService systemConfigService;
    private final WechatPayInfoService wechatPayInfoService;

    @Override
    @SuppressWarnings("unchecked")
    public PlatformResponse.ReturnValue refund(StoreOrderRefundRequest request, StoreOrder storeOrder) throws IOException {

        PlatformResponse.ReturnValue data = new PlatformResponse.ReturnValue();

//        赋值
        String apiDomain = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_API_URL);
        Refund refund = new Refund();
        refund.setOutTradeNo(storeOrder.getOutTradeNo());
        refund.setOutRefundNo(CrmebUtil.getOrderNo("orderRefund"));
        refund.setRefundFee(request.getAmount().toString());
        refund.setRefundNotifyUrl(apiDomain + BankEnterpriseConstants.BTE_NOTIFY_REFUND_URI);

//        entity转map
        Map<String, Object> result = JsonUtils.getObjectMapper().readValue(JsonUtils.getObjectMapper().writeValueAsString(refund), Map.class);
        String sign = generateSignature(result);
//        添加签名
        refund.setSign(sign);
//        entity转为json
        String body = JsonUtils.toJsonString(refund);
        log.info("发起退款申请参数如下: --------->" + body);

        OkHttpClient client = new OkHttpClient().newBuilder().build();
        MediaType mediaType = MediaType.parse("application/json");
        assert body != null;
        RequestBody requestBody = RequestBody.create(body, mediaType);
        Request req = new Request.Builder()
                .url(BankEnterpriseConstants.PREFIX + BankEnterpriseConstants.REFUND_URI)
                .post(requestBody)
                .addHeader("Content-Type", "application/json")
                .build();

        Response response = client.newCall(req).execute();
        if (ObjectUtil.isNotNull(response.body())) {
            String te = response.body().string();
            log.error("得到的结果是:------->" + te);
            PlatformResponse platformResponse = JsonUtils.parseObject(te, PlatformResponse.class);
            assert platformResponse != null;
            if (platformResponse.getSuccess()) {
                data = platformResponse.getReturnValue();
            } else {
                throw new CrmebException(platformResponse.getErrorCode() + platformResponse.getErrorMessage());
            }
        }
        return data;
    }

    @Override
    public Boolean queryPayResult(String orderNo) {

        return true;
    }

    @Override
    public PlatformResponse.ReturnValue preorderRecharge(UserRecharge recharge, String ip) throws IOException {

        if (ObjectUtil.isNull(recharge)) {
            throw new CrmebException("订单不存在");
        }
        // 获取用户openId
        // 根据订单支付类型来判断获取公众号openId还是小程序openId
        UserToken userToken = new UserToken();
        if (recharge.getRechargeType().equals(PayConstants.PAY_CHANNEL_WE_CHAT_PUBLIC)) {// 公众号
            userToken = userTokenService.getTokenByUserId(recharge.getUid(), 1);
        }
        if (recharge.getRechargeType().equals(PayConstants.PAY_CHANNEL_WE_CHAT_PROGRAM)) {// 小程序
            userToken = userTokenService.getTokenByUserId(recharge.getUid(), 2);
        }
        if (recharge.getRechargeType().equals(PayConstants.PAY_CHANNEL_WE_CHAT_H5)) {// H5
            userToken.setToken("");
        }

        if (ObjectUtil.isNull(userToken)) {
            throw new CrmebException("该用户没有openId");
        }

        // 获取appid、mch_id
        // 微信签名key
        String storeId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_BTE_STORE_ID);
        String appId = "";
        String mchId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_BTE_STORE_MCH_NO);
        WechatPayUniqueEntity payInfo = new WechatPayUniqueEntity();
        if (recharge.getRechargeType().equals(PayConstants.PAY_CHANNEL_WE_CHAT_PUBLIC)) {// 公众号
            appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID);
            payInfo.setOrderType("3");
        }
        if (recharge.getRechargeType().equals(PayConstants.PAY_CHANNEL_WE_CHAT_PROGRAM)) {// 小程序
            appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID);
            payInfo.setOrderType("4");
        }
        if (recharge.getRechargeType().equals(PayConstants.PAY_CHANNEL_WE_CHAT_H5)) {// H5,使用公众号的
            appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID);
            payInfo.setOrderType("3");
        }

        payInfo.setStoreId(storeId);
        payInfo.setSubAppid(appId);
        payInfo.setSubMerchantNo(mchId);

        payInfo.setSubject("充值服务");
        payInfo.setBody("本次充值金额:" + "-" + recharge.getPrice() + "元");
        payInfo.setOutTradeNo(recharge.getOrderId());
        payInfo.setTotalAmount(recharge.getPrice());
        payInfo.setUserId(userToken.getToken());
//        payInfo.setExtend(new Extend(Constants.SERVICE_PAY_TYPE_RECHARGE, recharge.getUid()));

        payInfo.setSubsidyFee(new BigDecimal(0));
        payInfo.setPayPlatformType("2");
        payInfo.setPullUpType(1);
        String apiDomain = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_API_URL);
        payInfo.setNotifyUrl(apiDomain + BankEnterpriseConstants.BTE_NOTIFY_URI);
        return prepay(payInfo);
    }

    @Override
    public PlatformResponse.ReturnValue preOrder(StoreOrder order, String ip) throws IOException {

        if (ObjectUtil.isNull(order)) {
            throw new CrmebException("订单不存在");
        }

        // 获取用户openId
        // 根据订单支付类型来判断获取公众号openId还是小程序openId
        UserToken userToken = new UserToken();

        // 获取appid、mch_id
        // 微信签名key
        String storeId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_BTE_STORE_ID);
        String appId = "";
        String mchId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_BTE_STORE_MCH_NO);
        WechatPayUniqueEntity payInfo = new WechatPayUniqueEntity();
        if (order.getIsChannel() == 0) {// 公众号
            userToken = userTokenService.getTokenByUserId(order.getUid(), 1);

            appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID);
            payInfo.setOrderType("3");
        }
        if (order.getIsChannel() == 1) {// 小程序
            userToken = userTokenService.getTokenByUserId(order.getUid(), 2);

            appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID);
            payInfo.setOrderType("4");
        }
        if (order.getIsChannel() == 2) {// H5
            userToken.setToken("");

            appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID);
            payInfo.setOrderType("3");
        }

        if (ObjectUtil.isNull(userToken)) {
            throw new CrmebException("该用户没有openId");
        }

        payInfo.setStoreId(storeId);
        payInfo.setSubAppid(appId);
        payInfo.setSubMerchantNo(mchId);

        String siteName = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_SITE_NAME);
        payInfo.setSubject(siteName);
        payInfo.setBody(siteName + "-商品订单");
        payInfo.setOutTradeNo(CrmebUtil.getOrderNo("wxNo"));
        payInfo.setTotalAmount(order.getPayPrice());
        payInfo.setUserId(userToken.getToken());
//        payInfo.setExtend(new Extend(Constants.SERVICE_PAY_TYPE_ORDER, order.getUid()));

        payInfo.setSubsidyFee(new BigDecimal(0));
        payInfo.setPayPlatformType("2");
        payInfo.setPullUpType(1);
        String apiDomain = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_API_URL);
        payInfo.setNotifyUrl(apiDomain + BankEnterpriseConstants.BTE_NOTIFY_URI);

//        交易过期时间
//        List<String> configKeys = new ArrayList<>();
//        configKeys.add("order_cancel_time");
//        configKeys.add("order_activity_time");
//        configKeys.add("order_bargain_time");
//        configKeys.add("order_seckill_time");
//        configKeys.add("order_pink_time");
//        List<String> configValues = systemConfigService.getValuesByKes(configKeys);
//        Date timeSpace;
//        timeSpace = DateUtil.addSecond(order.getCreateTime(),Double.valueOf(configValues.get(0)).intValue() * 3600);
//        payInfo.setTimeExpire(DateUtil.dateToStr(timeSpace, Constants.DATE_FORMAT));

        return prepay(payInfo);
    }

    /**
     * 统一预下单接口
     *
     * @param payInfo 支付信息
     * @return 平台响应结果
     */
    @SuppressWarnings("unchecked")
    private PlatformResponse.ReturnValue prepay(WechatPayUniqueEntity payInfo) throws IOException {

//        param转map
        Map<String, Object> result = JsonUtils.getObjectMapper().readValue(JsonUtils.getObjectMapper().writeValueAsString(payInfo), Map.class);
//        签名
        String sign = generateSignature(result);
        payInfo.setSign(sign);
//        log.info("完整支付参数如下: --------->" + payInfo);

        String body = JsonUtils.toJsonString(payInfo);
        log.info("发起支付参数如下: --------->" + body);
//        开始向银企发起请求
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        MediaType mediaType = MediaType.parse("application/json");
        assert body != null;
        RequestBody requestBody = RequestBody.create(body, mediaType);
        Request request = new Request.Builder()
                .url(BankEnterpriseConstants.PREFIX + BankEnterpriseConstants.PREPAY_URI)
                .post(requestBody)
                .addHeader("Content-Type", "application/json")
                .build();

        Response response = client.newCall(request).execute();
        if (ObjectUtil.isNotNull(response.body())) {
            String te = response.body().string();
            log.error("得到的结果是:------->" + te);
            PlatformResponse platformResponse = JsonUtils.parseObject(te, PlatformResponse.class);
            assert platformResponse != null;
            if (platformResponse.getSuccess()) {
//                保存支付参数
                WechatPayInfo wechatPayInfo = new WechatPayInfo();
                wechatPayInfo.setPrepayId(platformResponse.getReturnValue().getMiniPayInfo().getPackAge());
                wechatPayInfo.setNonceStr(platformResponse.getReturnValue().getMiniPayInfo().getNonceStr());
                wechatPayInfo.setSign(platformResponse.getReturnValue().getMiniPayInfo().getPaySign());
                wechatPayInfo.setSignType(platformResponse.getReturnValue().getMiniPayInfo().getSignType());
                wechatPayInfo.setAppId(platformResponse.getReturnValue().getMiniPayInfo().getAppId());
                wechatPayInfo.setTimeStart(platformResponse.getReturnValue().getMiniPayInfo().getTimeStamp());
                wechatPayInfo.setCodeUrl(platformResponse.getReturnValue().getQrCode());
                wechatPayInfo.setBody(payInfo.getSubject());
                wechatPayInfo.setDetail(payInfo.getBody());
                wechatPayInfo.setMchId(payInfo.getSubMerchantNo());
                wechatPayInfo.setOpenId(payInfo.getUserId());
                wechatPayInfo.setOutTradeNo(payInfo.getOutTradeNo());
                wechatPayInfo.setTotalFee(payInfo.getTotalAmount().multiply(new BigDecimal("100")).intValue());
                wechatPayInfo.setTimeExpire(payInfo.getTimeExpire());
                wechatPayInfo.setNotifyUrl(payInfo.getNotifyUrl());
                wechatPayInfoService.save(wechatPayInfo);
                return platformResponse.getReturnValue();
            } else {
                throw new CrmebException(platformResponse.getErrorCode() + platformResponse.getErrorMessage());
            }
        }
        return new PlatformResponse.ReturnValue();
    }

    private String generateSignature(Map<String, Object> result) {

        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<>(result.keySet());
        Collections.sort(keys);
        int index = 0;

        for (String s : keys) {
            Object value = result.get(s);
            if (ObjectUtil.isNotEmpty(value)) {
                content.append(index == 0 ? "" : "&").append(s).append("=").append(value);
                ++index;
            }
        }
        content.append(systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_BTE_STORE_KEY));

        return SHA256Utils.getSHA256(content.toString());
    }
}
